package com.gmrz.uaf.servlet.v1.handler;

import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.common.UAFException;
import com.gmrz.uaf.protocol.v1.json.UAFSchemaBuilder;
import com.gmrz.uaf.protocol.v1.processor.UAFDeviceProcessor;
import com.gmrz.uaf.protocol.v1.processor.exception.UAFErrorCode;
import com.gmrz.uaf.protocol.v1.schema.RegistrationRequest;
import com.gmrz.uaf.server.ServerContext;
import com.gmrz.uaf.servlet.v1.request.DeviceSupportContext;
import com.gmrz.uaf.servlet.v1.request.ReceiveReqPayload;
import com.gmrz.uaf.servlet.v1.response.DeviceSupportResponse;
import com.gmrz.uaf.servlet.v1.response.FidoRespPayload;
import com.gmrz.uaf.servlet.v1.validation.PayloadValidationException;
import com.gmrz.uaf.servlet.v1.validation.RestValidator;
import com.gmrz.util.Convert;
import com.gmrz.util.Strings;
import com.gmrz.util.UUIDGenerator;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by chentaikun on 16/12/19.
 */
public class UAFDeviceV2Handler extends UAFBaseHandler {

    private static final Logger LOG = LogManager.getLogger(UAFDeviceV2Handler.class);


    /**
     * {
     * "context":{"transNo":"","authType":"00","appID","001"}
     * }
     *
     * @param request {
     *                "statusCode":1000,
     *                "description":"xxxxxx",
     *                "uafRequest":[
     *                "{\“authType\”:\"00\",\”transType\”:\"00\",\”uafRequest\”: [{\"”header\"”:{...….}”,\”policcy\”:{…..}”}]}”,
     *                [”{\”authType\”:\"01\",\”transType\”:\"00\",\”uafRequest\”: [{\”headeer\”:{….}”,\”policcy\”:{…..}”}]}”
     *                ]
     *                }
     */
    public String deviceSupport(String request) {

        LOG.info("[/V2/device/support][begin]");
        ServerContext.getServerContext().getFidoLog().setRequest(request);
        FidoRespPayload<List<DeviceSupportResponse>> respPayload = new FidoRespPayload<List<DeviceSupportResponse>>();
        String response = null;

        try {

            Gson gson = UAFSchemaBuilder.getGson();
            Type reqType = new TypeToken<ReceiveReqPayload<DeviceSupportContext>>() {
            }
                    .getType();

            ReceiveReqPayload<DeviceSupportContext> reqPayload = gson.fromJson(request, reqType);
            ServerContext.getServerContext().setBase64(reqPayload.getContext().isBase64());

            logRequest(request, reqPayload.getContext().getTransNo(), reqPayload.getContext().getUserName(),
                    reqPayload.getContext().getAppID(), Strings.listToString(reqPayload.getContext().getAuthType()),null, Constants.Method.DEVICE_SUPPORT);
            checkUafRegStatus();
            //验证厂商白名单和设备黑名单
            validateDevice(reqPayload.getContext().getDevices(),reqPayload.getContext().getAppID());
            validate(reqPayload);
            UAFDeviceProcessor processor = GuiceUtil.getProcessorInjector().
                    getInstance(UAFDeviceProcessor.class);
            DeviceSupportContext context = reqPayload.getContext();
            String userID = UUIDGenerator.generateID();
            List<String> authTypes = context.getAuthType();
            List<String> transTypes = context.getTransType();
            List<DeviceSupportResponse> responses = new ArrayList<DeviceSupportResponse>();

            for (String authType : authTypes) {
                if (Constants.AuthType.isAuthType(authType)) {
                    for (String transType : transTypes) {
                        List<String> uafRequestList = new ArrayList<String>();
                        List<RegistrationRequest> requests = null;
                        try {
                            requests = processor.support(userID, authType, context.getAppID(), transType);
                        } catch (Exception e) {
                            //LOG.error(e);
                        }
                        if (null == requests) {
                            requests = new ArrayList<RegistrationRequest>();
                        }
                        requests = checkVendorAccept(requests,reqPayload.getContext().getDevices());
                        if(ServerContext.getServerContext().isBase64()) {
                            uafRequestList.add(Convert.toBase64(gson.toJson(requests).getBytes()));
                        }else {
                            uafRequestList.add(gson.toJson(requests));
                        }
                        DeviceSupportResponse deviceSupportResponse = new DeviceSupportResponse();
                        deviceSupportResponse.setAuthType(authType);
                        deviceSupportResponse.setTransType(transType);
                        deviceSupportResponse.setUafRequest(uafRequestList);
                        responses.add(deviceSupportResponse);
                        LOG.debug("getNamedPolicy authType:" + authType + ",appID:" + context.getAppID() + ",transType:" + transType + ",size:" + responses.size());
                    }
                } else {
                    throw new UAFException(UAFErrorCode.PROTOCOL_AUTH_TYPE_FAIL);
                }
            }
            LOG.debug("getNamedPolicy size:" + responses.size());
            respPayload.setStatusCode(1200);
            respPayload.setDescription("OK");
            respPayload.setUafRequest(responses);
            return gson.toJson(respPayload);
        } catch (Exception ex) {
            LOG.error(ex);
            response = buildFidoRespFromException(respPayload, ex);
        }
        LOG.info("[/V2/device/support][end]");
        return response;
    }

    private void validate(ReceiveReqPayload<DeviceSupportContext> reqPayload)
            throws PayloadValidationException {
        if ((reqPayload == null) || (reqPayload.getContext() == null)) {
            throw new PayloadValidationException("context", RestValidator.VALIDATION_ERROR.EMPTY);
        }
        List<String> authType = reqPayload.getContext().getAuthType();
        if (null == authType || authType.isEmpty()) {
            throw new PayloadValidationException("authType", RestValidator.VALIDATION_ERROR.EMPTY);
        }
        for (String a : authType) {
            RestValidator.validate("authType", a);
        }
        List<String> transType = reqPayload.getContext().getTransType();
        if (null == transType || transType.isEmpty()) {
            throw new PayloadValidationException("transType", RestValidator.VALIDATION_ERROR.EMPTY);
        }
        for(String t : transType){
            RestValidator.validate("transType", t);
        }
        String appID = reqPayload.getContext().getAppID();
        RestValidator.validate("appID", appID);
        RestValidator.validate("transNo", reqPayload.getContext().getTransNo());
        RestValidator.validateDevices(reqPayload.getContext().getDevices());
    }
}


